package com.card.server.utils;

import com.card.server.config.RedisService;
import com.card.server.domain.MatchUser;
import com.card.server.domain.Player;
import com.card.server.domain.Room;
import com.card.server.domain.UserEmitters;
import com.card.server.enums.TimeEnum;
import com.card.server.mapper.ChipMapper;
import com.card.server.mapper.UsersMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import reactor.core.publisher.FluxSink;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author TISNIW
 * @version 1.0
 * @date 2025/5/26 13:59
 * @desc 匹配工具类，基于虚拟等级匹配玩家，不修改真实等级
 */
@Component
public class MatchUtil {
    private static final Logger log = LoggerFactory.getLogger(MatchUtil.class);

    @Autowired
    private RedisService redisService;
    @Autowired
    private UsersMapper usersMapper;
    @Autowired
    private ChipMapper chipMapper;

    private static final String[] AI_NAME = {
            "星阑", "墨染", "浮生若梦", "夜微凉", "风居住的街道",
            "浅墨", "清风徐来", "半夏微光", "落樱缤纷时", "月下独酌",
            "北岛寒", "南笙一梦", "纸短情长", "流年似水", "灯火阑珊",
            "猫巷少女", "鲸落成山", "听风入眠", "雾失楼台", "故人不归",
            "旧梦如烟", "执笔画卿", "星辰有信", "鹿栖深林", "云淡风轻",
            "秋水共长天", "细水长流", "花未全开", "月到天心", "一念向北",
            "梦里花开", "岁月静好", "青衫客", "红尘笑笑生", "逆光而行",
            "风吹一夏", "你很特别", "时光煮雨", "浅笑安然", "与你共赏",
            "拾荒者", "孤影自怜", "繁星点点", "春风十里", "不如你",
            "星河滚烫", "你是人间", "醉卧江南", "纸上江南", "梦回长安",
            "指尖星光", "烟火迷途", "旧街故人", "晚风知我", "万物不及你",
            "听风说你", "温柔半两", "山高路远", "且听风吟", "人间值得",
            "小幸运", "时光旅人", "梦一场", "一叶知秋", "清风自来",
            "心动不如行动", "云卷云舒", "灯火可亲", "风中有你", "心之所向"
    };

    // 用于保存每个用户的虚拟等级（仅在匹配时使用）
    private Map<MatchUser, Integer> virtualLevelMap = new ConcurrentHashMap<>();

    public void checkMatchingUsers() {
        Map<String, List<MatchUser>> groupedUsers = new HashMap<>();

        // 1. 获取所有匹配池用户
        for (int game = 1; game <= 1; game++) { // 示例只支持 game=1（斗地主）
            for (int table = 1; table <= 4; table++) {
                String poolKey = buildPoolKey(game, table);
                Set<String> keys = redisService.getKeysByPattern(poolKey + "*");
                if (keys != null && !keys.isEmpty()) {
                    for (String key : keys) {
                        MatchUser user = redisService.getCacheObject(key, MatchUser.class);
                        if (user != null && user.getGameType() != null && user.getTableType() != null) {
                            log.info("用户数据:{}", user);
                            String groupKey = user.getGameType() + "_" + user.getTableType();
                            groupedUsers.computeIfAbsent(groupKey, k -> new ArrayList<>()).add(user);
                        } else {
                            log.warn("用户数据不完整，跳过匹配: {}", key);
                        }
                    }
                }
            }
        }

        // 2. 对每个分组执行匹配
        for (Map.Entry<String, List<MatchUser>> entry : groupedUsers.entrySet()) {
            String[] parts = entry.getKey().split("_");
            int gameType = Integer.parseInt(parts[0]);
            int tableType = Integer.parseInt(parts[1]);

            List<MatchUser> users = entry.getValue();

            // 计算虚拟等级
            List<MatchUser> virtualUsers = calculateVirtualLevels(users);

            // 根据虚拟等级排序并匹配
            List<List<MatchUser>> matchedGroups = matchByElo(virtualUsers, gameType);

            // 处理匹配结果
            handleMatchedGroups(matchedGroups, gameType, tableType);
        }
    }

    /**
     * 根据等待时间计算虚拟等级
     */
    private List<MatchUser> calculateVirtualLevels(List<MatchUser> users) {
        List<MatchUser> virtualUsers = new ArrayList<>();
        long now = System.currentTimeMillis();

        for (MatchUser user : users) {
            long waitTime = now - user.getJoinTime().getTime();
            int delta = (int) (waitTime / 2000); // 每2秒增加1点容忍度
            int virtualLevel = Math.max(0, Math.min(10000, user.getOriginalLevel() + delta));
            virtualLevelMap.put(user, virtualLevel);

            MatchUser copy = new MatchUser();
            copy.setId(user.getId());
            copy.setOriginalLevel(user.getOriginalLevel());
            copy.setWinRate(user.getWinRate());
            copy.setGameType(user.getGameType());
            copy.setTableType(user.getTableType());
            copy.setJoinTime(user.getJoinTime());

            virtualUsers.add(copy);
        }

        return virtualUsers;
    }

    /**
     * 根据虚拟等级进行 Elo 式匹配
     */
    private List<List<MatchUser>> matchByElo(List<MatchUser> users, int gameType) {
        List<List<MatchUser>> groups = new ArrayList<>();

        // 按照虚拟等级排序
        users.sort(Comparator.comparingInt(u -> getVirtualLevel(u)));

        while (!users.isEmpty()) {
            if (gameType == 1) {
                if (users.size() >= 3) {
                    groups.add(users.subList(0, 3));
                    users = users.subList(3, users.size());
                } else {
                    for (MatchUser u : users) {
                        if (System.currentTimeMillis() - u.getJoinTime().getTime() > 20000) {
                            List<MatchUser> group = new ArrayList<>();
                            group.add(u);
                            group.add(createAiUser(gameType, u.getTableType(), u.getOriginalLevel()));
                            group.add(createAiUser(gameType, u.getTableType(), u.getOriginalLevel()));
                            groups.add(group);
                            users.clear();
                            break;
                        }
                    }
                    break;
                }
            }
        }

        return groups;
    }

    private int getVirtualLevel(MatchUser user) {
        // 返回该用户的虚拟等级
        return virtualLevelMap.getOrDefault(user, user.getOriginalLevel());
    }

    private MatchUser createAiUser(int gameType, int tableType, int level) {
        MatchUser ai = new MatchUser();
        ai.setId(-1);
        ai.setOriginalLevel(level);
        ai.setWinRate(0.5);
        ai.setGameType(gameType);
        ai.setTableType(tableType);
        return ai;
    }

    private Integer getChip(int tableType) {
        Random random = new Random();
        switch (tableType) {
            case 1:

                return random.nextInt(500) + 500;
            case 2:
                return random.nextInt(500) + 500;
            case 3:
                return random.nextInt(1000) + random.nextInt(1000)  +10000;
            case 4:
                return random.nextInt(1000) + random.nextInt(1000)+random.nextInt(1000)+50000;
            default:
                return 500;
        }
    }

    private void handleMatchedGroups(List<List<MatchUser>> groups, int gameType, int tableType) {
        int roomNumber = 1;
        for (List<MatchUser> group : groups) {
            String roomId = UUID.randomUUID().toString().substring(0, 8);
            List<Player> players = new ArrayList<>();
            Random random = new Random(); // 随机数生成器
            for (MatchUser user : group) {
                Player player = new Player();
                player.setId(user.getId());
                if (user.getId() == -1){
                    int index = random.nextInt(AI_NAME.length);
                    player.setName(AI_NAME[index]);
                    Integer chip = getChip(tableType);
                    player.setChip(chip);
                    player.setStatus(1);
                }else{
                    player.setName(usersMapper.queryUsernameById(user.getId()));
                    player.setChip(chipMapper.queryById(Long.valueOf(user.getId())).getChip());
                    player.setStatus(0);
                }
                player.setLevel(getVirtualLevel(user));
                player.setWinRate(user.getWinRate());
                log.info("用户 {} 匹配成功", player.toString());
                players.add(player);
            }

            // 创建房间对象
            Room matchRoom = new Room(roomId, gameType, tableType, players);

            // 缓存房间信息
            String roomKey = gameType + ":" + tableType + ":" + roomId;
            redisService.setCacheObject(roomKey, matchRoom, TimeEnum.ONE_DAY);

            log.info("创建房间成功：{}", roomKey);
            roomNumber++;

            for (MatchUser user : group) {
                String userIdStr = String.valueOf(user.getId());
                FluxSink<String> emitter = UserEmitters.userEmitters.get(userIdStr);

                if (emitter != null && !emitter.isCancelled()) {
                    Map<String, Object> response = new HashMap<>();
                    response.put("status", 1);
                    response.put("message", "已为您匹配到对手！");
                    response.put("roomKey", roomKey);
                    response.put("timestamp", System.currentTimeMillis());

                    emitter.next(JsonUtils.writeValueAsString(response));

                    // 移除SSE连接
                    UserEmitters.userEmitters.remove(userIdStr);
                }

                // 删除Redis缓存
                String poolKey = buildPoolKey(user.getGameType(), user.getTableType());

                if (user.getId() != -1){
                    log.info("用户等级{}", user.getOriginalLevel());
                    log.info(poolKey + ":" + user.getId() + ":" + user.getOriginalLevel());
                    boolean deleted = redisService.deleteObject(poolKey + ":" + user.getId() + ":" + user.getOriginalLevel());
                    log.info("清除缓存:{}", deleted ? "成功" : "失败");
                }
            }
        }

        // 清空虚拟等级映射
        virtualLevelMap.clear();
    }

    private String buildPoolKey(int gameType, int tableType) {
        return "match:query:" + gameType + ":" + tableType;
    }
}